// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: daniel

#include "coin2/exchange/upbit/api_order/native_rest_async_asio_subscriber.h"

#include <glog/logging.h>

#include "coin2/base/time.h"
#include "coin2/exchange/order/upbit.pb.h"
#include "coin2/exchange/upbit/api_order/native_private_client.h"
#include "coin2/exchange/upbit/api_util/order_manager.h"

namespace coin2::exchange::upbit::api_order {

bool GetRateLimitPreventModeFromEnvVar() {
  char const* mode = getenv("RATE_LIMIT_SAVE_MODE");
  if (mode != nullptr && std::string(mode) == "1") {
    LOG(INFO) << "Set RATE_LIMIT_SAVE_MODE = true";
    return true;
  } else {
    LOG(INFO) << "Set RATE_LIMIT_SAVE_MODE = false";
    return false;
  }
}

void UpbitRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryAccountBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&UpbitRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void UpbitRestAsyncAsioSubscriber::QueryOpenOrders() {
  RestParams params;
  params.set_market("");
  params.set_state("open");  // tempo solution
  auto http_context = rest_client()->QueryOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&UpbitRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void UpbitRestAsyncAsioSubscriber::QueryAllOrders(const std::string& state) {
  RestParams params;
  params.set_market("");
  params.set_state(state);
  auto http_context = rest_client()->QueryOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&UpbitRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void UpbitRestAsyncAsioSubscriber::QueryFills() {
  if (query_fill_in_progress_) {
    return;
  }
  query_fill_in_progress_ = true;
  RestParams params;
  const auto open_orders = order_mgr_->GetOpenOrdersCopy();
  for (const auto& order_id : open_orders) {
    params.set_uuid(order_id);
    auto http_context = rest_client()->QueryTrades(params);
    if (!http_context) {
      continue;
    }
    http_context->handler =
        std::bind(&UpbitRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
    http_driver_->PostAsyncContext(http_context);
  }
  query_fill_in_progress_ = false;
}

void UpbitRestAsyncAsioSubscriber::SubscribeAsync() {
  auto rate_limit_prevent_mode = GetRateLimitPreventModeFromEnvVar();

  AddPeriodicTask(
      std::bind(&UpbitRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  if (rate_limit_prevent_mode) {
    AddPeriodicTask(
        std::bind(&UpbitRestAsyncAsioSubscriber::QueryAllOrders, this, std::placeholders::_1),
        config_.query_fill_period_sec(),
        "query_all_orders",
        all_states_);
  } else {
    AddPeriodicTask(
        std::bind(&UpbitRestAsyncAsioSubscriber::QueryOpenOrders, this),
        config_.query_open_orders_period_sec(),
        "query_open_orders");

    AddPeriodicTask(
        std::bind(&UpbitRestAsyncAsioSubscriber::QueryFills, this),
        config_.query_fill_period_sec(),
        "query_fills");
  }
}

}  // namespace coin2::exchange::upbit::api_order
